﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Windows.Forms;

namespace App
{

    [Designer(typeof(TabStripDesigner))]
    [DefaultEvent("TabStripItemSelectionChanged")]
    [DefaultProperty("Items")]
    [ToolboxItem(true)]
    public class TabStrip : BaseStyledPanel, ISupportInitialize, IDisposable
    {
        #region Static Members
        internal static int PreferredWidth = 350;
        internal static int PreferredHeight = 200;
        #endregion

        #region Constants
        private const int DEF_HEADER_HEIGHT = 29;
        private const int DEF_GLYPH_WIDTH = 40;

        private int DEF_START_POS = 10;
        #endregion

        #region Members
        private TabStripMenuGlyph menuGlyph = null;
        private TabStripCloseButton closeButton = null;
        private TabStripItemCollection items;
        private TabStripItem selectedItem = null;

        private Rectangle stripButtonRect = Rectangle.Empty;
        private Point cursorLoc = new Point(0, 0);
        private ContextMenuStrip menu = null;
        private ToolStripDropDownMenu rightClickMenu = null;

        private StringFormat sf = null;
        private static Font defaultFont = new Font("Tahoma", 8.25f, FontStyle.Regular);

        private bool alwaysShowClose = true;
        private bool isIniting = false;
        private bool alwaysShowMenuGlyph = true;
        private bool menuOpen = false;

        #region Hover & Color Members
        private Color selectedColor1;
        private Color selectedColor2;
		private Color selectedForeColor;

        private Color normalColor1;
        private Color normalColor2;
		private Color normalForeColor;

        private Color selectedBorderColor;
        private Color normalBorderColor;

        private TabStripItem currentHotItem = null;
        private TabStripItem hoverItem = null;
        #endregion
        #endregion

        #region Events
        public event TabStripItemMouseEnterHandler TabStripItemMouseEnter;
        public event TabStripItemMouseLeaveHandler TabStripItemMouseLeave;

        public event TabStripItemClosingHandler TabStripItemClosing;
        public event TabStripItemChangedHandler TabStripItemSelectionChanged;
        public event SelectedItemChangedHandler SelectedItemChanged;

        public event HandledEventHandler MenuItemsLoading;
        public event EventHandler MenuItemsLoaded;
        public event EventHandler TabStripItemClosed;
        #endregion

		#region Properties
		[DefaultValue(null)]
		[RefreshProperties(RefreshProperties.All)]
		public TabStripItem SelectedTab
		{
			get { return selectedItem; }
			set
			{
				if (selectedItem == value)
					return;

				if (value == null && Items.Count > 0)
				{
					TabStripItem itm = Items[0];
					if (itm.Visible)
					{
						selectedItem = itm;
						selectedItem.Selected = true;
						selectedItem.Dock = DockStyle.Fill;
					}
				}
				else
					selectedItem = value;

				foreach (TabStripItem itm in Items)
				{
					if (itm == selectedItem)
					{
						SelectItem(itm);
						itm.Dock = DockStyle.Fill;
						itm.Show();
					}
					else
					{
						UnSelectItem(itm);
						itm.Hide();
					}
				}

				SelectItem(selectedItem);
				Invalidate();

				if (!selectedItem.IsDrawn)
				{
					Items.MoveTo(0, selectedItem);
					Invalidate();
				}

				OnTabStripItemChanged(
					new TabStripItemChangedEventArgs(selectedItem, TabStripItemChangeTypes.SelectionChanged));
			}
		}

		[DefaultValue(true)]
		public bool AlwaysShowMenuGlyph
		{
			get { return alwaysShowMenuGlyph; }
			set
			{
				if (alwaysShowMenuGlyph == value)
					return;

				alwaysShowMenuGlyph = value;
				Invalidate();
			}
		}

		[DefaultValue(true)]
		public bool AlwaysShowClose
		{
			get { return alwaysShowClose; }
			set
			{
				if (alwaysShowClose == value)
					return;

				alwaysShowClose = value;
				Invalidate();
			}
		}

		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		public TabStripItemCollection Items
		{ get { return items; } }

		[DefaultValue(typeof(Size), "350,200")]
		public new Size Size
		{
			get { return base.Size; }
			set
			{
				if (base.Size == value)
					return;

				base.Size = value;
				UpdateLayout();
			}
		}

		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public new ControlCollection Controls
		{ get { return base.Controls; } }

		public ToolStripDropDownMenu RightClickMenu
		{
			get { return rightClickMenu; }
			set { rightClickMenu = value; }
		}

		public Color SelectedColorStart
		{
			get { return selectedColor1; }
			set
			{
				selectedColor1 = value;
				this.Invalidate();
			}
		}

		public Color SelectedColorEnd
		{
			get { return selectedColor2; }
			set
			{
				selectedColor2 = value;
				this.Invalidate();
			}
		}

		public Color SelectedBorderColor
		{
			get { return selectedBorderColor; }
			set
			{ 
				selectedBorderColor = value;
				this.Invalidate();
			}
		}

		public Color NormalColorStart
		{
			get { return normalColor1; }
			set
			{
				normalColor1 = value;
				this.Invalidate();
			}
		}

		public Color NormalColorEnd
		{
			get { return normalColor2; }
			set
			{
				normalColor2 = value;
				this.Invalidate();
			}
		}

		public Color NormalBorderColor
		{
			get { return normalBorderColor; }
			set
			{
				normalBorderColor = value;
				this.Invalidate();
			}
		}

		public Color NormalForeColor
		{
			get { return normalForeColor; }
			set
			{
				normalForeColor = value;
				this.Invalidate();
			}
		}

		public Color SelectedForeColor
		{
			get { return selectedForeColor; }
			set
			{
				selectedForeColor = value;
				this.Invalidate();
			}
		}
		#endregion

        #region Methods
        #region Public
        public HitTestResult HitTest(Point pt)
        {
            if (closeButton.Bounds.Contains(pt))
                return HitTestResult.CloseButton;

            if (menuGlyph.Bounds.Contains(pt))
                return HitTestResult.MenuGlyph;

            if (GetTabItemByPoint(pt) != null)
                return HitTestResult.TabItem;

            return HitTestResult.None;
        }

        public void AddTab(TabStripItem tabItem)
        {
            AddTab(tabItem, false);

            if (SelectedItemChanged != null)
                SelectedItemChanged(new TabStripItemMouseEventArgs(SelectedTab));

            // Update the currently shown controls.
            foreach (Control control in SelectedTab.Controls)
                control.Show();
        }

        public void AddTab(TabStripItem tabItem, bool autoSelect)
        {
            tabItem.Dock = DockStyle.Fill;
            tabItem.BackColor = Color.FromArgb(226, 236, 248);
            //
			tabItem.TabStripParent = this;
            Items.Add(tabItem);

            TabStripItemMouseEnter += new TabStripItemMouseEnterHandler(OnTabMouseEnter);
            TabStripItemMouseLeave += new TabStripItemMouseLeaveHandler(OnTabMouseLeave);

            if ((autoSelect && tabItem.Visible) || (tabItem.Visible && Items.DrawnCount < 1))
            {
                SelectedTab = tabItem;
                SelectItem(tabItem);

                if (SelectedItemChanged != null)
                    SelectedItemChanged(new TabStripItemMouseEventArgs(tabItem));

                // Update the currently shown controls.
                foreach (Control control in tabItem.Controls)
                    control.Show();
            }
        }

        public void RemoveTab(TabStripItem tabItem)
        {
            int tabIndex = Items.IndexOf(tabItem);

            TabStripItemMouseEnter -= new TabStripItemMouseEnterHandler(OnTabMouseEnter);
            TabStripItemMouseLeave -= new TabStripItemMouseLeaveHandler(OnTabMouseLeave);

            if (tabIndex >= 0)
            {
                UnSelectItem(tabItem);
                Items.Remove(tabItem);
            }

            if (Items.Count > 0)
            {
                if (RightToLeft == RightToLeft.No)
                {
                    if (Items[tabIndex - 1] != null)
                        SelectedTab = Items[tabIndex - 1];
                    else
                        SelectedTab = Items.FirstVisible;

                    if (SelectedItemChanged != null)
                        SelectedItemChanged(new TabStripItemMouseEventArgs(SelectedTab));

                    // Update the currently shown controls.
                    foreach (Control control in SelectedTab.Controls)
                        control.Show();
                }
                else
                {
                    if (Items[tabIndex + 1] != null)
                        SelectedTab = Items[tabIndex + 1];
                    else
                        SelectedTab = Items.LastVisible;

                    if (SelectedItemChanged != null)
                        SelectedItemChanged(new TabStripItemMouseEventArgs(SelectedTab));

                    // Update the currently shown controls.
                    foreach (Control control in SelectedTab.Controls)
                        control.Show();
                }
            }
        }

        public TabStripItem GetTabItemByPoint(Point pt)
        {
            TabStripItem item = null;
            bool found = false;

            for (int i = 0; i < Items.Count; i++)
            {
                TabStripItem current = Items[i];

                if (current.StripRect.Contains(pt) && current.Visible 
                    && current.IsDrawn)
                {
                    item = current;
                    found = true;
                }

                if (found)
                    break;
            }

            return item;
        }

        public virtual void ShowMenu()
        {
            if (menu.Visible == false && menu.Items.Count > 0)
            {
                if (RightToLeft == RightToLeft.No)
                    menu.Show(this, new Point(menuGlyph.Bounds.Left, 
                        menuGlyph.Bounds.Bottom));
                else
                    menu.Show(this, new Point(menuGlyph.Bounds.Right, 
                        menuGlyph.Bounds.Bottom));

                menuOpen = true;
            }
        }

		public void CheckHot()
		{
			foreach (TabStripItem item in Items)
			{
				if (item.IsHot == false &&
					currentHotItem == item)
				{
					currentHotItem = null;
					item.IsHot = false;
					if (TabStripItemMouseLeave != null)
					{
						TabStripItemMouseEventArgs args =
						new TabStripItemMouseEventArgs(item);
						TabStripItemMouseLeave(args);
					}
				}
				
				if (item.IsHot == true &&
					(item.StripRect.Contains(PointToClient(Cursor.Position)) == false ||
					 item.Bounds.Contains(PointToClient(Cursor.Position)) == true))
				{
					currentHotItem = null;
					item.IsHot = false;
					if (TabStripItemMouseLeave != null)
					{
						TabStripItemMouseEventArgs args =
						new TabStripItemMouseEventArgs(item);
						TabStripItemMouseLeave(args);
					}
				}
				if (item.StripRect.Contains(PointToClient(Cursor.Position)) == true)
				{
					currentHotItem = item;
					item.IsHot = true;
					if (TabStripItemMouseEnter != null)
					{
						TabStripItemMouseEventArgs args =
							new TabStripItemMouseEventArgs(item);
						TabStripItemMouseEnter(args);
					}
				}
			}
		}
        #endregion

        #region Internal
        internal void UnDrawAll()
        {
            for (int i = 0; i < Items.Count; i++)
            {
                Items[i].IsDrawn = false;
            }
        }

        internal void SelectItem(TabStripItem tabItem)
        {
            tabItem.Dock = DockStyle.Fill;
            tabItem.Visible = true;
            tabItem.Selected = true;
        }

        internal void UnSelectItem(TabStripItem tabItem)
        {
            tabItem.Selected = false;
        }
        #endregion

        #region Protected
        protected internal virtual void OnTabStripItemClosing(TabStripItemClosingEventArgs e)
        {
            if (TabStripItemClosing != null)
                TabStripItemClosing(e);
        }

        protected internal virtual void OnTabStripItemClosed(EventArgs e)
        {
            if (TabStripItemClosed != null)
                TabStripItemClosed(this, e);
        }

        protected virtual void OnMenuItemsLoading(HandledEventArgs e)
        {
            if (MenuItemsLoading != null)
                MenuItemsLoading(this, e);
        }

        protected virtual void OnMenuItemsLoaded(EventArgs e)
        {
            if (MenuItemsLoaded != null)
                MenuItemsLoaded(this, e);
        }

        protected virtual void OnTabStripItemChanged(TabStripItemChangedEventArgs e)
        {
            if (TabStripItemSelectionChanged != null)
                TabStripItemSelectionChanged(e);
        }

        protected virtual void OnMenuItemsLoad(EventArgs e)
        {
            menu.RightToLeft = RightToLeft;
            menu.Items.Clear();

            for (int i = 0; i < Items.Count; i++)
            {
                TabStripItem item = Items[i];
                if (!item.Visible)
                    continue;

                ToolStripMenuItem tItem = new ToolStripMenuItem(item.Title);
                tItem.Tag = item;
                tItem.Image = item.Image;
                menu.Items.Add(tItem);
            }

            OnMenuItemsLoaded(EventArgs.Empty);
        }
        #endregion

        #region Overrides
        protected override void OnRightToLeftChanged(EventArgs e)
        {
            base.OnRightToLeftChanged(e);
            UpdateLayout();
            Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            SetDefaultSelected();
            Rectangle borderRc = ClientRectangle;
            borderRc.Width--;
            borderRc.Height--;

            if (RightToLeft == RightToLeft.No)
                DEF_START_POS = 10;
            else
                DEF_START_POS = stripButtonRect.Right;


            Pen pen = new Pen(Color.FromArgb(141, 178, 227));


            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            //e.Graphics.DrawRectangle(pen, borderRc);
            //e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            #region Draw Pages
            for (int i = 0; i < Items.Count; i++)
            {
                TabStripItem currentItem = Items[i];
                if (!currentItem.Visible && !DesignMode)
                    continue;

                OnCalcTabPage(e.Graphics, currentItem);
                currentItem.IsDrawn = false;

                if (!AllowDraw(currentItem))
                    continue;

                OnDrawTabPage(e.Graphics, currentItem);
            }
            #endregion

            #region Draw UnderPage Line

            if (RightToLeft == RightToLeft.No)
            {
                if (Items.DrawnCount == 0 || Items.VisibleCount == 0)
                {
                    e.Graphics.DrawLine(pen, new Point(0, DEF_HEADER_HEIGHT),
                                        new Point(ClientRectangle.Width, DEF_HEADER_HEIGHT));
                }
                else if (SelectedTab != null && SelectedTab.IsDrawn)
                {
                    Point end = new Point((int)SelectedTab.StripRect.Left - 9, DEF_HEADER_HEIGHT);
                    e.Graphics.DrawLine(pen, new Point(0, DEF_HEADER_HEIGHT), end);
                    end.X += (int)SelectedTab.StripRect.Width + 10;
                    e.Graphics.DrawLine(pen, end, new Point(ClientRectangle.Width, DEF_HEADER_HEIGHT));
                }
            }
            else
            {
                if (Items.DrawnCount == 0 || Items.VisibleCount == 0)
                {
                    e.Graphics.DrawLine(pen, new Point(0, DEF_HEADER_HEIGHT),
                                        new Point(ClientRectangle.Width, DEF_HEADER_HEIGHT));
                }
                else if (SelectedTab != null && SelectedTab.IsDrawn)
                {
                    Point end = new Point((int)SelectedTab.StripRect.Left, DEF_HEADER_HEIGHT);
                    e.Graphics.DrawLine(pen, new Point(0, DEF_HEADER_HEIGHT), end);
                    end.X += (int)SelectedTab.StripRect.Width + 20;
                    e.Graphics.DrawLine(pen, end, new Point(ClientRectangle.Width, DEF_HEADER_HEIGHT));
                }
            }
            #endregion

            #region Draw Menu and Close Glyphs
            if (AlwaysShowMenuGlyph || Items.DrawnCount > Items.VisibleCount)
                menuGlyph.DrawGlyph(e.Graphics);

            if (AlwaysShowClose || (SelectedTab != null && SelectedTab.CanClose))
                closeButton.DrawCross(e.Graphics);
            #endregion
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            HitTestResult result = HitTest(e.Location);
            if (result == HitTestResult.MenuGlyph)
            {
                HandledEventArgs args = new HandledEventArgs(false);
                OnMenuItemsLoading(args);

                if (!args.Handled)
                    OnMenuItemsLoad(EventArgs.Empty);

                ShowMenu();
            }
            else if (result == HitTestResult.CloseButton)
            {
                if (SelectedTab != null)
                {
                    TabStripItemClosingEventArgs args = new TabStripItemClosingEventArgs(SelectedTab);
                    OnTabStripItemClosing(args);
                    if (!args.Cancel && SelectedTab.CanClose)
                    {
                        RemoveTab(SelectedTab);
                        OnTabStripItemClosed(EventArgs.Empty);
                    }
                }
            }
            else if (result == HitTestResult.TabItem)
            {
                TabStripItem item = GetTabItemByPoint(e.Location);
                if (item != null)
                {
                    SelectedTab = item;
                    if (SelectedItemChanged != null)
                        SelectedItemChanged(new TabStripItemMouseEventArgs(item));

                    // Update the currently shown controls.
                    foreach (Control control in item.Controls)
                        control.Show();

                    // Somehow the right click doesn't work
                    // if we don't pass the thread to another
                    // function.
                    RightClick(e);
                }
            }

            Invalidate();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
			CheckHot();

            if (menuGlyph.Bounds.Contains(e.Location) == true)
            {
                menuGlyph.IsMouseOver = true;
                Invalidate(menuGlyph.Bounds);
            }
            else
            {
                if (menuGlyph.IsMouseOver == true && 
                    menuOpen == false)
                {
                    menuGlyph.IsMouseOver = false;
                    Invalidate(menuGlyph.Bounds);
                }
            }

            if (closeButton.Bounds.Contains(e.Location) == true)
            {
                closeButton.IsMouseOver = true;
                Invalidate(closeButton.Bounds);
            }
            else
            {
                if (closeButton.IsMouseOver == true)
                {
                    closeButton.IsMouseOver = false;
                    Invalidate(closeButton.Bounds);
                }
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            menuGlyph.IsMouseOver = false;
            Invalidate(menuGlyph.Bounds);

            closeButton.IsMouseOver = false;
            Invalidate(closeButton.Bounds);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (isIniting)
                return;

            UpdateLayout();
        }
        #endregion

        #region Private
        #region Non-drawing Methods
        private void RightClick(MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Right:
                    if (rightClickMenu == null) { return; }

                    Point point = new Point(e.X, e.Y);
                    rightClickMenu.Show(this, point);

                    break;
                case MouseButtons.Left:
                    break;
            }
        }

        private bool AllowDraw(TabStripItem item)
        {
            bool result = true;

            if (RightToLeft == RightToLeft.No)
            {
                if (item.StripRect.Right >= stripButtonRect.Width)
                    result = false;
            }
            else
            {
                if (item.StripRect.Left <= stripButtonRect.Left)
                    return false;
            }

            return result;
        }

        private void SetDefaultSelected()
        {
            if (selectedItem == null && Items.Count > 0)
                SelectedTab = Items[0];

            for (int i = 0; i < Items.Count; i++)
            {
                TabStripItem itm = Items[i];
                itm.Dock = DockStyle.Fill;
            }
        }

        private void OnMenuItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            TabStripItem clickedItem = (TabStripItem)e.ClickedItem.Tag;
            SelectedTab = clickedItem;

            if (SelectedItemChanged != null)
                SelectedItemChanged(new TabStripItemMouseEventArgs(clickedItem));

            // Update the currently shown controls.
            foreach (Control control in clickedItem.Controls)
                control.Show();
        }

        private void OnMenuVisibleChanged(object sender, EventArgs e)
        {
            if (menu.Visible == false)
            {
                menuOpen = false;
            }
        }

        private void OnCollectionChanged(object sender, CollectionChangeEventArgs e)
        {
            TabStripItem itm = (TabStripItem)e.Element;

            if (e.Action == CollectionChangeAction.Add)
            {
                Controls.Add(itm);
                OnTabStripItemChanged(new TabStripItemChangedEventArgs(itm, TabStripItemChangeTypes.Added));
            }
            else if (e.Action == CollectionChangeAction.Remove)
            {
                Controls.Remove(itm);
                OnTabStripItemChanged(new TabStripItemChangedEventArgs(itm, TabStripItemChangeTypes.Removed));
            }
            else
            {
                OnTabStripItemChanged(new TabStripItemChangedEventArgs(itm, TabStripItemChangeTypes.Changed));
            }

            UpdateLayout();
            Invalidate();
        }
        #endregion

        private void OnCalcTabPage(Graphics g, TabStripItem currentItem)
        {
            Font currentFont = Font;
            if (currentItem == SelectedTab)
                currentFont = new Font(Font, FontStyle.Bold);

            SizeF textSize = g.MeasureString(currentItem.Title, currentFont, new SizeF(200, 10), sf);
            textSize.Width += 40;

            if (RightToLeft == RightToLeft.No)
            {
                RectangleF buttonRect = new RectangleF(DEF_START_POS, 3, textSize.Width, DEF_HEADER_HEIGHT - 2);
                currentItem.StripRect = buttonRect;
                DEF_START_POS += (int)textSize.Width;
            }
            else
            {
                RectangleF buttonRect = new RectangleF(DEF_START_POS - textSize.Width + 1, 3, textSize.Width - 1, 17);
                currentItem.StripRect = buttonRect;
                DEF_START_POS -= (int)textSize.Width;
            }
        }

        private void OnDrawTabPage(Graphics g, TabStripItem currentItem)
        {
            bool isFirstTab = Items.IndexOf(currentItem) == 0;
            Font currentFont = Font;

            if (currentItem == SelectedTab)
                currentFont = new Font(Font, FontStyle.Bold);

            SizeF textSize = g.MeasureString(currentItem.Title, currentFont, new SizeF(200, 10), sf);
            textSize.Width += 30;
            RectangleF buttonRect = currentItem.StripRect;

            GraphicsPath path = new GraphicsPath();
            LinearGradientBrush brush;
            int mtop = 3;

            if (currentItem == SelectedTab || isFirstTab)
            {
                path.AddLine(buttonRect.Left - 10, buttonRect.Bottom - 1,
                    buttonRect.Left + (buttonRect.Height / 2) - 3, mtop + 2);
            }
            else
            {
                path.AddLine(buttonRect.Left, buttonRect.Bottom - 1, buttonRect.Left,
                    buttonRect.Bottom - (buttonRect.Height / 2) - 3);
                path.AddLine(buttonRect.Left, buttonRect.Bottom - (buttonRect.Height / 2) - 1,
                    buttonRect.Left + (buttonRect.Height / 2) - 3, mtop + 2);
            }

            path.AddLine(buttonRect.Left +
                (buttonRect.Height / 2) + 2, mtop,
                buttonRect.Right - 3, mtop);
            path.AddLine(buttonRect.Right, mtop + 2,
                buttonRect.Right, buttonRect.Bottom - 1);
            path.AddLine(buttonRect.Right - 4,
                buttonRect.Bottom - 1, buttonRect.Left,
                buttonRect.Bottom - 1);
            path.CloseFigure();

            if (currentItem == currentHotItem &&
                currentHotItem.IsHot == true)
            {
                brush = new LinearGradientBrush(buttonRect,
                    selectedColor1, selectedColor2,
                    LinearGradientMode.Vertical);

                g.FillPath(brush, path);
                g.DrawPath(new Pen(selectedBorderColor), path);

                g.DrawLine(new Pen(brush), buttonRect.Left - 9, buttonRect.Height + 2,
                        buttonRect.Left + buttonRect.Width - 1, buttonRect.Height + 2);

                PointF textLoc = new PointF(buttonRect.Left + buttonRect.Height - 4,
                    buttonRect.Top + (buttonRect.Height / 2) - (textSize.Height / 2)
                    - 3);

                RectangleF textRect = buttonRect;
                textRect.Location = textLoc;
                textRect.Width = buttonRect.Width - (textRect.Left - buttonRect.Left) - 4;
                textRect.Height = textSize.Height + currentFont.Size / 2;

                g.DrawString(currentHotItem.Title, currentFont,
                    new SolidBrush(selectedForeColor), textRect, sf);

                brush.Dispose();
            }
            else
            {
                if (currentItem == SelectedTab)
                {
                    brush = new LinearGradientBrush(buttonRect,
                        selectedColor1, selectedColor2,
                        LinearGradientMode.Vertical);
                }
                else
                {
                    brush = new LinearGradientBrush(buttonRect,
                        normalColor1, normalColor2,
                        LinearGradientMode.Vertical);
                }

                g.FillPath(brush, path);
                if (currentItem == SelectedTab)
                    g.DrawPath(new Pen(selectedBorderColor), path);
                else
                    g.DrawPath(new Pen(normalBorderColor), path);

                if (currentItem == SelectedTab)
                {
                    g.DrawLine(new Pen(brush), buttonRect.Left - 9, buttonRect.
                        Height + 2, buttonRect.Left + buttonRect.Width - 1,
                        buttonRect.Height + 2);
                }

                PointF textLoc = new PointF(buttonRect.Left + buttonRect.Height - 4,
                    buttonRect.Top + (buttonRect.Height / 2) - (textSize.Height / 2)
                    - 3);

                RectangleF textRect = buttonRect;
                textRect.Location = textLoc;

                textRect.Height = textSize.Height + currentFont.Size / 2;
                textRect.Width = buttonRect.Width - (textRect.Left -
                    buttonRect.Left) - 4;

                if (currentItem == SelectedTab)
                {
                    g.DrawString(currentItem.Title, currentFont, new SolidBrush
                        (selectedForeColor), textRect, sf);
                }
                else
                {
                    g.DrawString(currentItem.Title, currentFont, new SolidBrush
                        (normalForeColor), textRect, sf);
                }
                brush.Dispose();

            }

            path.Dispose();

            currentItem.IsDrawn = true;
        }

        private void UpdateLayout()
        {
            if (RightToLeft == RightToLeft.No)
            {
                sf.Trimming = StringTrimming.EllipsisCharacter;
                sf.FormatFlags |= StringFormatFlags.NoWrap;
                sf.FormatFlags &= StringFormatFlags.DirectionRightToLeft;

                stripButtonRect = new Rectangle(0, 0, ClientSize.Width - DEF_GLYPH_WIDTH - 2, 10);
                menuGlyph.Bounds = new Rectangle(ClientSize.Width - DEF_GLYPH_WIDTH, 4, 16, 16);
                closeButton.Bounds = new Rectangle(ClientSize.Width - 20, 4, 16, 16);
            }
            else
            {
                sf.Trimming = StringTrimming.EllipsisCharacter;
                sf.FormatFlags |= StringFormatFlags.NoWrap;
                sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;

                stripButtonRect = new Rectangle(DEF_GLYPH_WIDTH + 2, 0, ClientSize.Width - DEF_GLYPH_WIDTH - 15, 10);
                closeButton.Bounds = new Rectangle(4, 2, 16, 16);
                menuGlyph.Bounds = new Rectangle(20 + 4, 2, 16, 16);
            }

            DockPadding.Top = DEF_HEADER_HEIGHT + 1;
            DockPadding.Bottom = 1;
            DockPadding.Right = 1;
            DockPadding.Left = 1;
        }

        #region Tab EventHandlers
        private void OnTabMouseEnter(TabStripItemMouseEventArgs e)
        { Invalidate(); }

        private void OnTabMouseLeave(TabStripItemMouseEventArgs e)
        { Invalidate(); }
        #endregion
        #endregion
        #endregion

        #region ShouldSerialize
        public bool ShouldSerializeFont()
        {
            return Font != null && !Font.Equals(defaultFont);
        }

        public bool ShouldSerializeSelectedItem()
        {
            return true;
        }

        public bool ShouldSerializeItems()
        {
            return items.Count > 0;
        }

        public new void ResetFont()
        {
            Font = defaultFont;
        }
        #endregion

        #region ISupportInitialize Members
        public void BeginInit()
        {
            isIniting = true;
        }

        public void EndInit()
        {
            isIniting = false;
        }
        #endregion

        #region IDisposable
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                items.CollectionChanged -= new CollectionChangeEventHandler(OnCollectionChanged);
                menu.ItemClicked -= new ToolStripItemClickedEventHandler(OnMenuItemClicked);
                menu.VisibleChanged -= new EventHandler(OnMenuVisibleChanged);

                foreach (TabStripItem item in items)
                {
                    if (item != null && !item.IsDisposed)
                        item.Dispose();
                }

                if (menu != null && !menu.IsDisposed)
                    menu.Dispose();

                if (sf != null)
                    sf.Dispose();
            }

            base.Dispose(disposing);
        }
        #endregion

		/// <summary>
		/// Initializes the TabStrip.
		/// </summary>
		public TabStrip()
		{
			BeginInit();

			SetStyle(ControlStyles.ContainerControl, true);
			SetStyle(ControlStyles.UserPaint, true);
			SetStyle(ControlStyles.ResizeRedraw, true);
			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
			SetStyle(ControlStyles.Selectable, true);

			items = new TabStripItemCollection();
			items.CollectionChanged += new CollectionChangeEventHandler(OnCollectionChanged);
			base.Size = new Size(350, 200);

			menu = new ContextMenuStrip();
            menu.Renderer = new App.Office2007Renderer(); ;
			menu.ItemClicked += new ToolStripItemClickedEventHandler(OnMenuItemClicked);
			menu.VisibleChanged += new EventHandler(OnMenuVisibleChanged);

			menuGlyph = new TabStripMenuGlyph(ToolStripRenderer);
			closeButton = new TabStripCloseButton(ToolStripRenderer);
			Font = defaultFont;
			sf = new StringFormat();

			normalColor1 = Color.FromArgb(227, 239, 255);
            normalColor2 = Color.FromArgb(226, 236, 248);
			normalBorderColor = normalColor2;

			selectedColor1 = Color.FromArgb(255, 255, 255);
            selectedColor2 = Color.FromArgb(226, 236, 248);
			selectedBorderColor = normalColor2;

			selectedForeColor = System.Drawing.Color.FromArgb(21, 66, 139);
            normalForeColor = System.Drawing.Color.FromArgb(21, 66, 139);

			EndInit();

			UpdateLayout();
		}
    }
}